////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_MATRIX_44_H__
#define __WN_MATRIX_44_H__

#include "WNCore/inc/WNBase.h"

namespace WNMath {
    class WNQuaternion;
    class WNVector3;
    class WNVector4;
    class WNPoint3;

    class WNMatrix44 {
    public:
        WNMatrix44();
        explicit WNMatrix44(const WN_FLOAT32* _f);
        explicit WNMatrix44(const WNVector3& _vector1,
                            const WNVector3& _vector2,
                            const WNVector3& _vector3,
                            const WNVector3& _vector4);
        explicit WNMatrix44(WN_FLOAT32 _m11, WN_FLOAT32 _m12, WN_FLOAT32 _m13, WN_FLOAT32 _m14,
                            WN_FLOAT32 _m21, WN_FLOAT32 _m22, WN_FLOAT32 _m23, WN_FLOAT32 _m24,
                            WN_FLOAT32 _m31, WN_FLOAT32 _m32, WN_FLOAT32 _m33, WN_FLOAT32 _m34,
                            WN_FLOAT32 _m41, WN_FLOAT32 _m42, WN_FLOAT32 _m43, WN_FLOAT32 _m44);

        operator WN_FLOAT32* ();
        operator const WN_FLOAT32* () const;

        WN_FLOAT32& operator () (WN_INT32 _row, WN_INT32 _column);
        WN_FLOAT32 operator () (WN_INT32 _row, WN_INT32 _column) const;

        WNMatrix44& operator *= (const WNMatrix44& _matrix);
        WNMatrix44& operator += (const WNMatrix44& _matrix);
        WNMatrix44& operator -= (const WNMatrix44& _matrix);
        WNMatrix44& operator *= (WN_FLOAT32 _f);
        WNMatrix44& operator /= (WN_FLOAT32 _f);

        WNMatrix44 operator + () const;
        WNMatrix44 operator - () const;

        WNMatrix44 operator * (const WNMatrix44& _matrix) const;
        WNMatrix44 operator + (const WNMatrix44& _matrix) const;
        WNMatrix44 operator - (const WNMatrix44& _matrix) const;
        WNMatrix44 operator * (WN_FLOAT32 _f) const;
        WNMatrix44 operator / (WN_FLOAT32 _f) const;

        friend WNMatrix44 operator * (WN_FLOAT32 _f, const WNMatrix44& _matrix);
        friend WNMatrix44 operator / (WN_FLOAT32 _f, const WNMatrix44& _matrix);

        WN_BOOL operator == (const WNMatrix44& _matrix) const;
        WN_BOOL operator != (const WNMatrix44& _matrix) const;

        WNPoint3  Transform(const WNPoint3& _point) const;
        WNVector3 Transform(const WNVector3& _vector) const;
        WNVector4 Transform(const WNVector4& _point) const;

        WN_VOID Zero();
        WN_VOID Identity();
        WN_VOID Transpose();
        WN_BOOL Invert();

        WN_FLOAT32 Determinant() const;
        WN_FLOAT32 Trace() const;

        WN_BOOL IsIdentity() const;
        WN_BOOL IsSymmetric() const;
        WN_BOOL IsDiagonal() const;
        WN_BOOL IsRotated() const;

        WN_VOID Set(const WN_FLOAT32* _f);
        WN_VOID Set(WN_FLOAT32 _m11, WN_FLOAT32 _m12, WN_FLOAT32 _m13, WN_FLOAT32 _m14,
                    WN_FLOAT32 _m21, WN_FLOAT32 _m22, WN_FLOAT32 _m23, WN_FLOAT32 _m24,
                    WN_FLOAT32 _m31, WN_FLOAT32 _m32, WN_FLOAT32 _m33, WN_FLOAT32 _m34,
                    WN_FLOAT32 _m41, WN_FLOAT32 _m42, WN_FLOAT32 _m43, WN_FLOAT32 _m44);
        WN_VOID SetRow(WN_UINT8 _row, const WNVector4& _data);
        WN_VOID SetColumn(WN_UINT8 _column, const WNVector4& _data);

        WNMatrix44 GetTransposed() const;
        WNMatrix44 GetInverted() const;
        WNMatrix44 GetAdjugate() const;
        WNVector4 GetRow(WN_UINT8 _row) const;
        WNVector4 GetColumn(WN_UINT8 _column) const;

        WNQuaternion ToQuaternion() const;

    public:
        union {
            struct {
                WN_FLOAT32 _11, _12, _13, _14;
                WN_FLOAT32 _21, _22, _23, _24;
                WN_FLOAT32 _31, _32, _33, _34;
                WN_FLOAT32 _41, _42, _43, _44;
            };

            WN_FLOAT32 raw1D[16];
            WN_FLOAT32 raw2D[4][4];
        };
    };
}

#endif // __WN_MATRIX_44_H__